<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        .box{width:350px;position: relative;margin: 20px;}
        .l_box{width:350px;height:350px;}
        .l_box span{position: absolute;left:0;top:0;background: rgba(255,0,0,0.5);display: none;}
        .r_box{width:350px;height:350px;position: absolute;left:370px;top:0;overflow: hidden;display:none;}
        .r_box img{position: absolute;left:0;top:0;}
    </style>
</head>
<body>
    <div class="box">
        <div class="l_box">
            <img src="./imgs/m0.jpg" alt="">
            <span></span>
        </div>
        <div class="r_box">
            <img src="./imgs/l0.jpg" alt="">
        </div>    
    </div>
</body>
<script>
    function BigImg(){
        // 2. 选择元素
        this.span = document.querySelector(".l_box span");
        this.lImg = document.querySelector(".l_box img");
        this.rImg = document.querySelector(".r_box img");
        this.rBox = document.querySelector(".r_box");
        this.lBox = document.querySelector(".l_box");
        this.box = document.querySelector(".box");
        

        // 3. 绑定事件
        this.addEvent()
    }
    BigImg.prototype = {
        addEvent(){
            const that = this;
            // 进入事件
            this.lBox.onmouseover = function(){
                // 4. 显示功能
                that.show()
            }
            // 离开事件
            this.lBox.onmouseout = function(){
                // 5. 隐藏功能
                that.hide()
            }
            // 移动事件
            this.lBox.onmousemove = function(eve){
                const e = eve || window.event;
                // 6. 移动功能
                that.move(e);
            }
        },
        show(){
            // 显示
            this.rBox.style.display = "block";
            this.span.style.display = "block";

            // 小坑：
            // 如果某个元素在css中设置了display:none那么js无法完全控制
            // 需要先display非none后，再控制这个元素

            if(this.span.offsetWidth !== 0) return;
            // 提前获取将来需要控制的各个元素的尺寸属性
            this.rbw = this.rBox.offsetWidth;
            this.riw = this.rImg.offsetWidth;
            this.rbh = this.rBox.offsetHeight;
            this.rih = this.rImg.offsetHeight;
            this.lbw = this.lBox.offsetWidth;
            this.lbh = this.lBox.offsetHeight;
            // 计算遮罩层的尺寸：右侧容器 / 右侧图片 * 左侧容器
            this.span.style.width = this.rbw / this.riw * this.lbw + "px";
            this.span.style.height = this.rbh / this.rih * this.lbh + "px";
        },
        hide(){
            // 隐藏
            this.rBox.style.display = "none";
            this.span.style.display = "none";
        },
        move(e){
            // 7. 计算鼠标移动距离
            let l = e.pageX-this.box.offsetLeft - this.span.offsetWidth/2;
            let t = e.pageY-this.box.offsetTop - this.span.offsetHeight/2;
            // 边界限定
            if(l < 0) l=0;      // 左
            if(t < 0) t=0;      // 上
            // 右
            if( l > this.lbw - this.span.offsetWidth ){
                l = this.lbw - this.span.offsetWidth
            }
            // 下
            if( t > this.lbh - this.span.offsetHeight ){
                t = this.lbh - this.span.offsetHeight
            }
            // 8. 设置给遮罩层
            this.span.style.left = l + "px";
            this.span.style.top = t + "px";
            // 9. 计算移动的比例；10. 根据比例计算右侧要移动的距离；11. 设置给大图
            // 公式：
            // 左侧能移动的总值：左侧容器 - 左侧span
            // 右侧能移动的总值：右侧容器 - 右侧图片
            // 鼠标移动距离 / 左侧能移动的总值 * 右侧能移动的总值
            this.rImg.style.left = l / (this.lbw - this.span.offsetWidth) * (this.rbw-this.riw) + "px";
            this.rImg.style.top = t / (this.lbh - this.span.offsetHeight) * (this.rbh-this.rih) + "px";
        }
    }
    new BigImg()
</script>
</html>